﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;

namespace zijian666.WebApi
{
    /// <summary>
    /// WebApi选项组
    /// </summary>
    public partial class WebApiOptions : IStartupFilter
    {
        private readonly Dictionary<string, Action<IApplicationBuilder>> _configures = new(StringComparer.OrdinalIgnoreCase);
        private readonly IServiceCollection _services;
        // 日志
        private ILogger? _logger;

        /// <summary>
        /// <seealso cref="IMvcBuilder"/>
        /// </summary>
        public IMvcBuilder MvcBuilder { get; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="mvcBuilder"></param>
        public WebApiOptions(IMvcBuilder mvcBuilder)
        {
            MvcBuilder = mvcBuilder ?? throw new ArgumentNullException(nameof(mvcBuilder));
            MvcBuilder.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
            _services = MvcBuilder.Services;
            _services.TryAddSingleton(this);
            _services.AddSingleton<IStartupFilter>(this);
        }

        private partial void FillTraceIdentifier(HttpContext context);

        private partial void EnableBuffering(HttpContext context);

        private Task Middleware(HttpContext context, Func<Task> next)
        {
            FillTraceIdentifier(context);
            EnableBuffering(context);
            return next();
        }

        /// <summary>
        /// 添加服务装配后操作
        /// </summary>
        /// <param name="key"></param>
        /// <param name="handler"></param>
        public void AddConfigureHandler(string key, Action<IApplicationBuilder> handler) => _configures[key?.ToLowerInvariant() ?? ""] = handler;

        internal void Configure(IApplicationBuilder app)
        {
            _logger = app.ApplicationServices.GetService<ILogger<WebApiOptions>>();
            app.Use(Middleware);
            var configures = new Dictionary<string, Action<IApplicationBuilder>>(_configures);
            foreach (var (name, handler) in _configures)
            {
                try
                {
                    _logger?.LogInformation($"正在装配服务:{name}");
                    handler?.Invoke(app);
                    _logger?.LogInformation($"服务装配完成:{name}");
                }
                catch (Exception e)
                {
                    _logger?.LogError(e, $"服务装配异常:{name}\n{e}");
                }
            }
        }

        Action<IApplicationBuilder> IStartupFilter.Configure(Action<IApplicationBuilder> next)
        {
            return app =>
            {
                Configure(app);
                next(app);
            };
        }
    }
}
